package com.springcloudalibaba.gateway.filter.global;

import com.springcloudalibaba.baseredis.service.RedissonSingleService;
import com.springcloudalibaba.bclass.base.BaseLoginUserInfo;
import com.springcloudalibaba.bclass.base.BaseResult;
import com.springcloudalibaba.bclass.constant.SysKeyConstant;
import com.springcloudalibaba.bclass.enums.SysStateEnum;
import com.springcloudalibaba.bclass.enums.SysKeyEnum;
import com.springcloudalibaba.bclass.util.JwtUtil;
import com.springcloudalibaba.bclass.util.LoggerUtil;
import com.springcloudalibaba.bclass.util.StrUtil;
import com.springcloudalibaba.gateway.enums.GatewayFilterOrderEnum;
import com.springcloudalibaba.gateway.properties.CustomProperties;
import com.springcloudalibaba.gateway.util.MonoResponseUtil;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.function.Consumer;

/**
 * @描述: TODO 认证全局过滤器，不需要在配置文件中配置，作用于所有的请求
 * @作者: lixing
 * @日期 2021/6/17 9:06
 */
@Component
public class MyAuthorizeGlobalFilter implements GlobalFilter, Ordered {
    @Resource
    private CustomProperties customProperties;

    @Resource
    private RedissonSingleService<String> redissonSingleServiceString;

    /**
     * 过滤器执行的顺序，值越小，执行顺序越靠前
     */
    @Override
    public int getOrder() {
        return GatewayFilterOrderEnum.MY_AUTHORIZE.getValue();
    }

    /**
     * TODO 全局“前置”过滤器逻辑
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest serverHttpRequest = exchange.getRequest();
        ServerHttpResponse serverHttpResponse = exchange.getResponse();

        /*
         * 请求白名单过滤
         */
        //   /login/**      匹配 /login 开头
        //   /trip/api/*x   匹配 /trip/api/x，/trip/api/ax，/trip/api/abx ；但不匹配 /trip/abc/x
        //   /trip/a/a?x    匹配 /trip/a/abx；但不匹配 /trip/a/ax，/trip/a/abcx
        //   /**/api/alie   匹配 /trip/api/alie，/trip/dax/api/alie；但不匹配 /trip/a/api
        //   /**/*.htmlm    匹配所有以.htmlm结尾的路径
        // 当前请求的地址，格式：
        // 127.0.0.1:8763/SpringCloudAlibabaDemo/gatewayAuth/auth/login
        // /gatewayAuth/auth/login
        String reqPath = serverHttpRequest.getURI().getPath();
        PathMatcher pathMatcher = new AntPathMatcher();
        for (String authIgnoreTemp : customProperties.getIgnore().getAuth().split(",")) {
            if (StrUtil.isEffective(authIgnoreTemp) && pathMatcher.match(authIgnoreTemp, reqPath)) {
                return chain.filter(exchange);
            }
        }

        /*
         * 对请求进行拦截并校验TOKEN
         */
        String token = serverHttpRequest.getHeaders().getFirst(SysKeyEnum.TOKEN.getKey());
        LoggerUtil.info("MyAuthorizeGlobalFilter 认证全局过滤器 ---- start");
        LoggerUtil.info(MessageFormat.format("当前token: {0}", token));
        LoggerUtil.info("MyAuthorizeGlobalFilter 认证全局过滤器 ---- end");
        LoggerUtil.info("");
        // 非空校验
        if (!StrUtil.isEffective(token)) {
            // 拦截，提示未授权错误，401
            //serverHttpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
            // 拦截结束请求
            //return serverHttpResponse.setComplete();
            return MonoResponseUtil.getVoidMono(serverHttpResponse, new BaseResult<String>().fail("TOKEN缺失"));
        }

        // 校验token，获取用户的登录对象
        try {
            BaseLoginUserInfo baseLoginUserInfo = JwtUtil.verifyJwtForHs256(token);

            // redis中校验登录状态 SpringCloudAlibabaDemo:login:version:admin
            String versionKey = MessageFormat.format(SysKeyEnum.LOGIN_USER_VERSION.getKey(), SysKeyConstant.PROJECTNAME, baseLoginUserInfo.getAccount());
            if (!redissonSingleServiceString.isExists(versionKey)) {
                // redis中没有当前key，则表示登录超时了，需要重写登录
                return MonoResponseUtil.getVoidMono(serverHttpResponse, new BaseResult<String>().fail(SysStateEnum.RESPONSE_STATUS_FALSE_TOKEN_TIMEOUT.getDescribe()));
            } else {
                // 判断当前的version和redis中的version是否一致，不一致则表示当前已经有人登录，需要重新登录
                String tokenVersion = redissonSingleServiceString.getKey(versionKey);
                if (!baseLoginUserInfo.getVersion().equals(tokenVersion)) {
                    return MonoResponseUtil.getVoidMono(serverHttpResponse, new BaseResult<String>().fail(SysStateEnum.RESPONSE_STATUS_FALSE_TOKEN_EXISTS.getDescribe()));
                }
            }

            // 修改请求求
            Consumer<HttpHeaders> httpHeaders = httpHeader -> {
                httpHeader.set(SysKeyEnum.USERINFO_ACCOUNT.getKey(), baseLoginUserInfo.getAccount());
                httpHeader.set(SysKeyEnum.USERINFO_PHONE.getKey(), baseLoginUserInfo.getPhone());
                httpHeader.remove(SysKeyEnum.TOKEN.getKey());
            };
            // 从原始交换对象获得一个新的 ServerHttpRequest 实例
            ServerHttpRequest serverHttpRequestMutable = serverHttpRequest.mutate().headers(httpHeaders).build();
            // 从原始交换对象获得一个新的 ServerWebExchange 实例
            ServerWebExchange serverWebExchangeMutable = exchange.mutate().request(serverHttpRequestMutable).build();
            //
            return chain.filter(serverWebExchangeMutable).then(Mono.fromRunnable(() -> {
                // TODO 全局“后置”过滤器逻辑
            }));
        } catch (Exception e) {
            return MonoResponseUtil.getVoidMono(serverHttpResponse, new BaseResult<String>().fail(e.getMessage()));
        }
    }

}
